package server.service;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import server.config.YamlConfig;
import server.entity.user.User;
import server.http.HttpResponseContent;
import server.mapper.LoginMapper;
import server.tool.CharType;
import server.tool.RedisTool;
import server.tool.Tool;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class LoginService {
    @Resource
    private Tool tool;
    @Resource
    private RedisTool redisTool;
    @Resource
    private LoginMapper loginMapper;
    @Resource
    private YamlConfig yamlConfig;

    // 手机号登录
    public JSONObject login(HashMap<String, Object> body, HttpServletRequest request) {
        String tell_phone = StrUtil.toString(body.getOrDefault("tellphone", null));
        String code = StrUtil.toString(body.getOrDefault("code", null));
        if (StrUtil.isNotEmpty(tell_phone) && StrUtil.isNotEmpty(code)) {
            JSONObject res;
            boolean tellIsLeal = tool.RegTellPhone(tell_phone);
            boolean codeIsLeal = tool.RegSixCode(code);
            if (BooleanUtil.isFalse(tellIsLeal)) {
                res = HttpResponseContent.LOGIN_INFO.get("pwd_err", JSONObject.class).set("msg", "手机号格式错误");
            } else if (BooleanUtil.isFalse(codeIsLeal)) {
                res = HttpResponseContent.LOGIN_INFO.get("pwd_err", JSONObject.class).set("msg", "验证码错误");
            } else {
                // 验证验证码是否错误
                String ip = request.getRemoteHost();
                if (tool.containsCode(ip)) {
                    CharSequence cacheCode = tool.getCode(ip);// 获取缓存code
                    if (StrUtil.equals(cacheCode, code)) {
                        // 验证码通过
                        String userId;
                        int hasUserByTell = loginMapper.hasUserByTell(tell_phone);
                        Console.log(hasUserByTell);
                        if (hasUserByTell > 0) { // 手机用户已存在
                            HashMap<String, String> data = new HashMap<>();// 存在就直接登录
                            data.put("tell_phone", tell_phone);
                            User userInfo = loginMapper.tellLogin(data);
                            userId = userInfo.getUser_id();
                            // 获取信息
                            String decrypt = tool.Encrypt(userId);
                            String token = tool.createToken("id", decrypt, yamlConfig.getExpire());
                            // 需要处理一下登录的token 为空的问题
                            boolean save = saveLoginStatusToCache(userId, token);
                            if (save) {
                                res = HttpResponseContent.LOGIN_INFO.get("success", JSONObject.class).set("msg", "登录成功").putOnce("token", token);
                            } else {
                                res = HttpResponseContent.LOGIN_INFO.get("res_success", JSONObject.class).set("msg", "登录失败").putOnce("token", token);
                            }
                        } else {
                            // 不存在就注册
                            HashMap<String, String> data = new HashMap<>();
                            String user_id = RandomUtil.randomString(4) + RandomUtil.randomNumbers(6);
                            String account = LocalDateTimeUtil.format(LocalDate.now(), "yyyyMMDD") + RandomUtil.randomNumbers(4);// 账户
                            String password = RandomUtil.randomString(CharType.NUMBER.getContent(), 8); // 8位数密码
                            userId = user_id;
                            data.put("user_id", user_id);
                            data.put("password", password);
                            data.put("account", account);
                            data.put("tell_phone", tell_phone);
                            int row = loginMapper.register(data);
                            if (row > 0) {
                                String decrypt = tool.Encrypt(userId);
                                String token = tool.createToken("id", decrypt, yamlConfig.getExpire());
                                boolean save = saveLoginStatusToCache(userId, token);
                                if (save) {
                                    res = HttpResponseContent.LOGIN_INFO.get("res_success", JSONObject.class).set("msg", "登录成功").putOnce("token", token);
                                } else {
                                    res = HttpResponseContent.LOGIN_INFO.get("res_success", JSONObject.class).set("msg", "登录失败").putOnce("token", token);
                                }
                            } else {
                                res = HttpResponseContent.LOGIN_INFO.get("fail", JSONObject.class).set("msg", "注册失败");
                            }
                        }
                    } else {
                        // 验证码错误
                        res = HttpResponseContent.LOGIN_INFO.get("fail", JSONObject.class).set("msg", "验证码错误");
                    }
                } else {
                    // 验证码过期
                    res = HttpResponseContent.LOGIN_INFO.get("pwd_err", JSONObject.class).set("msg", "验证码已过期");
                }
                tool.delCode(ip); // 作废
            }
            return res;
        } else {
            return HttpResponseContent.LOGIN_INFO.get("pwd_err", JSONObject.class).set("msg", "验证码或手机号验证失败");
        }
    }

    private boolean saveLoginStatusToCache(String userId, String token) {
        return redisTool.save_string(userId, token, yamlConfig.getExpire(), TimeUnit.DAYS); // 保存登录状态到缓存中
    }

    public JSONObject verityLoginStatus(String token) {
        boolean invalid = tool.verityToken(token); // 验证token 是否有效
        JWT praseToken = tool.parseToken(token);
        JSONObject res;
        if (invalid && ObjUtil.isNotNull(praseToken)) {
            Object id = praseToken.getPayload("id");
            if (ObjUtil.isNotNull(id) && StrUtil.isNotEmpty(id.toString())) {
                String strId = StrUtil.utf8Str(id);
                try {
                    String decryptId = tool.Decrypt(strId);// 解密id
                    boolean hasKey = redisTool.hasKey(decryptId);
                    if (StrUtil.isNotEmpty(decryptId) && hasKey) {
                        String randToken = RandomUtil.randomString(10);// 生成随机令牌 备用
                        res = HttpResponseContent.LOGIN_INFO.get("success", JSONObject.class).putOnce("t_ud", randToken);
                    } else {
                        res = HttpResponseContent.LOGIN_INFO.get("expire", JSONObject.class);
                    }
                } catch (Exception err) {
                    res = HttpResponseContent.LOGIN_INFO.get("expire", JSONObject.class);
                }
            } else {
                res = HttpResponseContent.LOGIN_INFO.get("expire", JSONObject.class);
            }
        } else {
            res = HttpResponseContent.LOGIN_INFO.get("expire", JSONObject.class);
        }
        return res;
    }

    public JSONObject logout(HttpServletRequest request) {
        JSONObject res;
        String getToken = request.getHeader("Token");
        if (StrUtil.isEmptyIfStr(getToken)) {
            res = HttpResponseContent.LOGIN_INFO.get("logout", JSONObject.class)
                    .set("code", 7)
                    .set("msg", "退出异常");
        } else {
            JWT jwt = tool.parseToken(getToken);
            String getId = StrUtil.utf8Str(jwt.getPayload("id"));
            try {
                String decodeId = tool.Decrypt(getId); // 解码
                redisTool.del_string(decodeId);
                res = HttpResponseContent.LOGIN_INFO.get("logout", JSONObject.class);
            } catch (Exception e) {
                res = HttpResponseContent.LOGIN_INFO.get("logout", JSONObject.class)
                        .set("code", 7)
                        .set("msg", e.getCause());
            }
        }
        return res;
    }
}
